%{
#include <stdio.h>
#include "tabelas.c"
int yylex();
int yydebug=1;
int errors = 0;
int linhas = 1;
int errorMes = 0;
int n = 0;
int coment = 0;
simbo *tab_sim;
simbo sim;
int indice;
int erroSemantico = 0;
int comand = -1;
%}

%start programa

%token PBEGIN
%token CONST
%token DOIS_PONTOS
%token END
%token IDENT
%token IGUAL
%token INTEGER 
%token PONTO
%token PONTO_VIRGULA
%token PROGRAM 
%token PROCEDURE
%token REAL
%token VAR
%token VIRGULA
%token ABRE_PARANTESES
%token FECHA_PARANTESES
%token ELSE
%token READLN
%token WRITELN
%token REPEAT 
%token UNTIL
%token IF 
%token THEN 
%token ATRIBUICAO
%token WHILE 
%token DO 
%token DIFERENTE
%token MAIOR_IGUAL
%token MENOR_IGUAL
%token MAIOR
%token MENOR
%token SINAL_MAIS
%token SINAL_MENOS
%token SINAL_MULTI
%token SINAL_DIV
%token COMENTARIO
%token ABRE_COMENTARIO
%token FECHA_COMENTARIO

%%

//Por enquanto só temos a adição e verificação dos identificadores na tabela de símbolos
//Falta verificar a parte dos argumentos em procedimentos...



programa        : PROGRAM IDENT PONTO_VIRGULA corpo PONTO				
		;
///////////////////////////////////////////////////////////////////////////////////////////////
corpo		: dc PBEGIN comandos END
		;
////////////////////////////////////////////////////////////////////////////////////////////////
dc		: dc_c dc_v dc_p
		;
//////////////////////////////////////////////////////////////////////////////////////////////
dc_c		: CONST IDENT IGUAL numero PONTO_VIRGULA dc_c

		| /*vazio*/

		;
//////////////////////////////////////////////////////////////////////////////////////////
dc_v		: VAR 
			{comand = VAR;}
				variaveis DOIS_PONTOS tipo_var PONTO_VIRGULA dc_v
		
		| /*vazio*/

		;
//////////////////////////////////////////////////////////////////////////////////////////
tipo_var	: REAL {atualizaTabela(tab_sim, &n, "real");}
 
		| INTEGER {atualizaTabela(tab_sim, &n, "integer");}
		
		;
//////////////////////////////////////////////////////////////////////////////////////////
variaveis	: IDENT 
			{if(comand == VAR){
				if(!buscaElem(tab_sim, sim.id, n, &indice) && !segurada(sim.id)){seguraVar(sim.id);} //Segura as variáveis, pois ainda não se sabe o tipo
				else{erroSem("Variável", sim.id,"já declarada");}}
			else
			if(!buscaElem(tab_sim, sim.id, n, &indice)){erroSem("Variável", sim.id, "não declarada");}}
				mais_var
		;
//////////////////////////////////////////////////////////////////////////////////////////
mais_var	: VIRGULA variaveis
		
		| /*vazio*/

		;
////////////////////////////////////////////////////////////////////////////////////////// 
dc_p		: PROCEDURE IDENT 

			//Pensar em como adicionar e verificar os parâmetros na tabela

				parametros PONTO_VIRGULA corpo_p dc_p	

		| /*vazio*/

		;
//////////////////////////////////////////////////////////////////////////////////////////////////////
parametros	: ABRE_PARANTESES lista_par FECHA_PARANTESES  				

		| /*vazio*/

		;
///////////////////////////////////////////////////////////////////////////////////////////////////////
lista_par	: variaveis DOIS_PONTOS tipo_var mais_par

		;
//////////////////////////////////////////////////////////////////////////////////////////////////////
mais_par	: PONTO_VIRGULA lista_par

		| /*vazio*/

		;
//////////////////////////////////////////////////////////////////////////////////////////////////////
corpo_p		: dc_loc PBEGIN comandos END PONTO_VIRGULA

		;
//////////////////////////////////////////////////////////////////////////////////////
dc_loc		: dc_v	
			
		;
/////////////////////////////////////////////////////////////////////////////////////
lista_arg	: ABRE_PARANTESES argumentos FECHA_PARANTESES 		
		
		| /*vazio*/

		;
////////////////////////////////////////////////////////////////////////////////////////
argumentos	: IDENT mais_ident

		;
/////////////////////////////////////////////////////////////////////////////////////////
mais_ident	: PONTO_VIRGULA argumentos
	
		| /*vazio*/

		;
///////////////////////////////////////////////////////////////////////////////////////
pfalsa		: ELSE cmd

		| /*vazio*/

		;
//////////////////////////////////////////////////////////////////////////////////////
comandos 	: cmd PONTO_VIRGULA comandos

		|  /*vazio*/

		;
//////////////////////////////////////////////////////////////////////////////////////
cmd 		: READLN 
			{comand = READLN;}
				ABRE_PARANTESES variaveis FECHA_PARANTESES {liberaVar();}
					
///////////////////////////
		| WRITELN ABRE_PARANTESES variaveis FECHA_PARANTESES

////////////////////////////
		| REPEAT comandos UNTIL condicao 
					
////////////////////////////
		| IF condicao THEN cmd pfalsa

///////////////////////////
		
		| IDENT {seguraVar(sim.id);} ATRIBUICAO expressao {if(buscaElem(tab_sim, auxVar[0], n, &indice)){
									if(!verificaTipo(tab_sim[indice].tipo)){erroSem("Resultado ", "real", "em inteiro");}}
					     		           else{erroSem("Variável", auxVar[0], "não declarada");}}

//////////////////////////
		| IDENT lista_arg 

/////////////////////////
		| PBEGIN comandos END

//////////////////////////////////////////
		| WHILE ABRE_PARANTESES condicao FECHA_PARANTESES DO cmd 
		;
///////////////////////////////////////////////////////////////ok
condicao	: expressao relacao expressao
		
		;
////////////////////////////////////////////////////////////////ok
relacao		: IGUAL 
		| DIFERENTE 
		| MAIOR_IGUAL
		| MENOR_IGUAL
		| MAIOR
		| MENOR	
	
		;
///////////////////////////////////////////////////////////////////
expressao	: termo outros_termos	
		
		;
/////////////////////////////////////////////////////////////////
op_un		: SINAL_MAIS {seguraOp('+');}

		| SINAL_MENOS {seguraOp('-');}	

		| /*vazio*/
		;
/////////////////////////////////////////////////////////////////
outros_termos	: op_ad termo outros_termos
		| /*vazio*/
		;
////////////////////////////////////////////////////////////
op_ad		: SINAL_MAIS
		| SINAL_MENOS

		;
////////////////////////////////////////////////////////////////
termo 		: op_un fator 
				{if(comand == IDENT){
					if(buscaElem(tab_sim, sim.id, n, &indice)){seguraIndiceTipo(tab_sim, indice);}
					else{erroSem("Variável", sim.id, "não declarada");}}}

					mais_fatores		
		;
///////////////////////////////////////////////////////////////
mais_fatores 	: op_mul fator mais_fatores
		| /*vazio*/
		;
////////////////////////////////////////////////////////////
op_mul 		: SINAL_MULTI
		| SINAL_DIV

		;
//////////////////////////////////////////////////////////////
fator		: IDENT {comand = IDENT;}
		| numero
		| ABRE_PARANTESES expressao FECHA_PARANTESES

		;
////////////////////////////////////////////////////////////
numero		: INTEGER
		| REAL
		;
		
%%
#include "lex.yy.c"

int main(){

  
  tab_sim = (simbo*) malloc(MAX_SIMBO*sizeof(simbo));
  inicializaTipo(tab_tipo);
  inicializaPalavrasReservadas(reservadas);
	
  yyparse();

  if(coment == 1){
	printf("Comentário não fechado\n");
	errorMes = 1;
  }
		

  if(!errorMes && !erroSemantico)
	printf("\nCompilado com sucesso\n\n");
  else
	printf("\nFalha de compilação\n\n");
	

return 0;
}

erroSem(char *s1, char *var, char *s2){

	erroSemantico = 1;
	if(!coment)
		printf("%d: %s %s %s\n", yylineno, s1, var, s2);

}

yyerror(char *s){

	errorMes  = 1;
	if(!coment)
		printf("%d: %s\n", yylineno, s);
}

	
